package com.qf.aop.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.core.utils.FileUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: sin
 * @Date: 2025/5/15 21:34
 * @Description: @RequestParam、@PathVariable、@RequestBody 注解 请求参数获取
 **/
@Slf4j
public class AopParamResolver {

    public static final int MAX_DATA_LENGTH = 512;

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static String resolveMethodParamsToJson(JoinPoint joinPoint) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            String[] paramNames = signature.getParameterNames();
            Object[] paramValues = joinPoint.getArgs();
            Annotation[][] annotations = method.getParameterAnnotations();

            if (paramNames == null || paramValues == null) {
                return null;
            }

            Map<String, Object> paramMap = getParamMap(paramValues, paramNames, annotations);

            return truncate(objectMapper.writeValueAsString(paramMap));
        } catch (Exception e) {
            log.warn("解析请求参数失败", e);
            return null;
        }
    }

    /**
     * 解析  @RequestParam、@PathVariable、@RequestBody
     **/
    private static Map<String, Object> getParamMap(Object[] paramValues, String[] paramNames, Annotation[][] annotations) {
        Map<String, Object> paramMap = new LinkedHashMap<>();

        for (int i = 0; i < paramValues.length; i++) {
            Object value = paramValues[i];
            if (isIgnoredType(value)) continue;

            String defaultName = paramNames[i];
            Annotation[] paramAnnotations = annotations[i];
            boolean handled = false;

            for (Annotation annotation : paramAnnotations) {
                if (annotation instanceof RequestParam req) {
                    String name = !req.value().isEmpty() ? req.value() : defaultName;
                    paramMap.put(name, value);
                    handled = true;
                    break;
                } else if (annotation instanceof PathVariable pv) {
                    String name = !pv.value().isEmpty() ? pv.value() : defaultName;
                    paramMap.put(name, value);
                    handled = true;
                    break;
                } else if (annotation instanceof RequestBody) {
                    paramMap.put("body", value);
                    handled = true;
                    break;
                }
            }
            if (!handled) {
                // 如果是 MultipartFile，单独处理
                if (value instanceof MultipartFile file) {
                    paramMap.put(defaultName, FileUtils.extractMultipartInfo(file));
                } else {
                    paramMap.put(defaultName, value);
                }
            }
        }
        return paramMap;
    }

    private static boolean isIgnoredType(Object o) {
        return o instanceof HttpServletRequest
                || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }

    private static String truncate(String s) {
        return s.length() > MAX_DATA_LENGTH ? s.substring(0, MAX_DATA_LENGTH) : s;
    }
}